package com.ctshk.rpc.finance.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ctshk.common.dto.Result;
import com.ctshk.common.enums.SysApprovalType;
import com.ctshk.common.enums.SystemBusinessType;
import com.ctshk.common.enums.SystemError;
import com.ctshk.common.exception.BusinessException;
import com.ctshk.common.model.PageResponse;
import com.ctshk.common.utils.CharUtil;
import com.ctshk.common.utils.DateUtil;
import com.ctshk.common.utils.EntityUtil;
import com.ctshk.common.utils.SnowflakeIdWorker;
import com.ctshk.rpc.booking.dto.SupplierOrderDTO;
import com.ctshk.rpc.booking.service.ISupplierOrderService;
import com.ctshk.rpc.finance.dto.paidin.*;
import com.ctshk.rpc.finance.dto.special.SupplierOrderSourceDTO;
import com.ctshk.rpc.finance.dto.supplier.ReconciliationDTO;
import com.ctshk.rpc.finance.entity.FinancePaidIn;
import com.ctshk.rpc.finance.entity.FinancePaidInDetail;
import com.ctshk.rpc.finance.json.FileJson;
import com.ctshk.rpc.finance.mapper.FinancePaidInDetailMapper;
import com.ctshk.rpc.finance.mapper.FinancePaidInMapper;
import com.ctshk.rpc.finance.mapper.FinanceSupplierReconciliationDetailMapper;
import com.ctshk.rpc.finance.req.paidin.*;
import com.ctshk.rpc.finance.service.IFinancePaidInService;
import com.ctshk.rpc.system.dto.UserDTO;
import com.ctshk.rpc.system.service.ISysUserService;
import com.ctshk.rpc.workflow.dto.ApprovalCheckDTO;
import com.ctshk.rpc.workflow.dto.ApprovalStartDTO;
import com.ctshk.rpc.workflow.service.ISysApprovalService;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;


import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;

/**
 * <p>
 * 财务实付 服务实现类
 * </p>
 *
 * @author 叶冠峰
 * @since 2021-04-12
 */
@DubboService
public class FinancePaidInServiceImpl extends ServiceImpl<FinancePaidInMapper, FinancePaidIn> implements IFinancePaidInService {

    @Autowired
    private FinancePaidInMapper paidInMapper;
    @Autowired
    private FinancePaidInDetailMapper paidInDetailMapper;
    @Autowired
    private FinanceSupplierReconciliationDetailMapper supplierReconciliationDetailMapper;

    /*@Autowired
    private RedisTemplate<String, Object> redisTemplate;*/

    @DubboReference
    private ISysApprovalService sysApprovalService;
    @DubboReference
    private ISysUserService sysUserService;
    //供应商预订单
    @DubboReference
    private ISupplierOrderService supplierOrderService;



    /**
     * 列表
     *
     * @param req
     * @return
     */
    @Override
    public Result<PageResponse<PaidInListDTO>> list(PaidInListReq req) {
        Page<PaidInListDTO> iPage = new Page<>(req.getPageNo(), req.getPageSize());
        Page<PaidInListDTO> page = paidInMapper.queryListByCondition(req,iPage);
        if (CollectionUtils.isEmpty(page.getRecords())) {
            return Result.success(PageResponse.empty(page.getCurrent()));
        }
        page.getRecords().forEach(dto -> {
            //查询创建人
//            UserDTO userDto = (UserDTO) redisTemplate.opsForValue().get(RedisConstants.ACCOUNT_QUERY_KEY + dto.getCreateId());
            UserDTO userDto = sysUserService.queryCacheUser(dto.getCreateId());
            if (userDto != null){
                dto.setCreateUserName(userDto.getFullName());
                dto.setCreateUserDept(userDto.getDept());
            }
        });
        PageResponse<PaidInListDTO> result = new PageResponse<>(
                page.getRecords(),
                page.getCurrent() == 1,
                page.getTotal() <= (page.getCurrent() * page.getSize()),
                page.getTotal(),
                page.getCurrent(),
                page.getSize());
        return Result.success(result);
    }

    /**
     * 详情
     *
     * @param req
     * @return
     */
    @Override
    public Result<PaidInDTO> detail(PaidInIdReq req) {
        FinancePaidIn paidIn = getById(req.getId());
        if (paidIn == null || Objects.equals(paidIn.getIsDeleted(),1)){
            throw new BusinessException(SystemError.FINANCE_PAIDIN_17029);
        }
        PaidInDTO dto = EntityUtil.copy(paidIn,PaidInDTO.class);
        //附件
        if (StringUtils.isNotBlank(paidIn.getFilesJson())){
            dto.setFilesJson(JSON.parseArray(paidIn.getFilesJson(), FileJson.class));
        }
        //付款預訂單列表
        QueryWrapper<FinancePaidInDetail> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("paid_in_id",paidIn.getId());
        queryWrapper.eq("is_deleted",0);
        List<FinancePaidInDetail> detailList = paidInDetailMapper.selectList(queryWrapper);
        if (CollectionUtils.isNotEmpty(detailList)){
            List<PaidInDetailDTO> list = new ArrayList<>();
            //币种金额统计
            List<PaidInAmountCountDTO> countList =  paidInDetailMapper.sumAmountByCurrency(paidIn.getId());
            if (CollectionUtils.isNotEmpty(countList)){
                dto.setCountList(countList);
            }
            detailList.forEach(detail -> {
                PaidInDetailDTO detailDTO = EntityUtil.copy(detail,PaidInDetailDTO.class);
                //查询创建人
//                UserDTO userDto = (UserDTO) redisTemplate.opsForValue().get(RedisConstants.ACCOUNT_QUERY_KEY + detail.getCreateId());
                UserDTO userDto = sysUserService.queryCacheUser(detail.getCreateId());
                if (userDto != null){
                    detailDTO.setCreateUserName(userDto.getFullName());
                    detailDTO.setCreateUserDept(userDto.getDept());
                }
                list.add(detailDTO);
            });
            //多少条数据
            dto.setSize(list.size());
            dto.setDetailList(list);
        }
        return Result.success(dto);
    }

    /**
     * 申请付款/编辑
     *
     * @param req
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result add(PaidInAddReq req) {
        FinancePaidIn paidIn = null;
        //操作（1 新增 2 修改）
        int operateType = 1;
        LocalDateTime now = LocalDateTime.now();
        if (req.getId() != null){
            operateType = 2;
            paidIn = getById(req.getId());
            if (paidIn == null || Objects.equals(paidIn.getIsDeleted(),1)){
                throw new BusinessException(SystemError.FINANCE_PAIDIN_17029);
            }
            paidIn.setModifiedId(req.getUserId());
            paidIn.setGmtModified(now);
        }else{
            //新增供应商实付
            paidIn = EntityUtil.copy(req,FinancePaidIn.class);
            paidIn.setId(SnowflakeIdWorker.nextId());
            //付款单号 FK+年後2位+月日4位+時分秒6位+4位随机数字
            String payNumber = "FK"+ DateUtil.fmt(now,"yyMMddHHmmss")+ CharUtil.getRandomStr(4);
            paidIn.setPayNumber(payNumber);
            paidIn.setPayStatus(0);
            paidIn.setCreateId(req.getUserId());
            paidIn.setGmtCreate(now);
            paidIn.setIsDeleted(0);
        }
        //附件
        if (CollectionUtils.isNotEmpty(req.getFilesJson())){
            paidIn.setFilesJson(JSON.toJSONString(req.getFilesJson()));
        }
        paidIn.setApprovalStatus(req.getType());
        if (operateType == 1){
            //新增
            boolean save = save(paidIn);
            if (!save){
                throw new BusinessException(SystemError.SYS_437);
            }
        }else{
            //修改
            boolean update = updateById(paidIn);
            if (!update){
                throw new BusinessException(SystemError.SYS_437);
            }
        }
        //批量新增实付明细
        List<FinancePaidInDetail> list = new ArrayList<>();
        for (PaidInDetailAddReq detailReq : req.getDetailReqList()){
            FinancePaidInDetail detail = EntityUtil.copy(detailReq,FinancePaidInDetail.class);
            detail.setId(SnowflakeIdWorker.nextId());
            detail.setPaidInId(paidIn.getId());
            detail.setCreateId(req.getUserId());
            detail.setGmtCreate(now);
            detail.setIsDeleted(0);
            list.add(detail);
        }
        if (list.size() > 0){
            Integer batch = paidInDetailMapper.insertBatchSomeColumn(list);
            if (batch < list.size()){
                throw new BusinessException(SystemError.SYS_437);
            }
        }
        //提交审批
        if (Objects.equals(req.getType(),2)){
            if (operateType == 2){
                //修改
                if (Objects.equals(paidIn.getApprovalStatus(),2) || Objects.equals(paidIn.getApprovalStatus(),3)){
                    throw new BusinessException(SystemError.FINANCE_CHARGE_17028);
                }
            }
            Long approvalId = startApproval(paidIn.getId(), paidIn.getId(), req.getUserId());
            paidIn.setApprovalId(approvalId);
            boolean update = updateById(paidIn);
            if (!update){
                throw new BusinessException(SystemError.SYS_437);
            }
        }
        return Result.success(paidIn.getId());
    }

    /**
     * 删除
     *
     * @param req
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result del(PaidInIdReq req) {
        //删除实付单
        FinancePaidIn paidIn = getById(req.getId());
        if (paidIn == null || Objects.equals(paidIn.getIsDeleted(),1)){
            throw new BusinessException(SystemError.FINANCE_PAIDIN_17029);
        }
        paidIn.setIsDeleted(1);
        paidIn.setModifiedId(req.getUserId());
        boolean update = updateById(paidIn);
        //批量删除实付单明细
        Integer del = paidInDetailMapper.cleanByPaidIn(paidIn.getId(),req.getUserId());
        if (!update || del <= 0){
            throw new BusinessException(SystemError.SYS_437);
        }
        return Result.success(paidIn.getId());
    }

    /**
     * 提交审批
     *
     * @param req
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result commit(PaidInIdReq req) {
        FinancePaidIn paidIn = getById(req.getId());
        if (paidIn == null || Objects.equals(paidIn.getIsDeleted(),1)){
            throw new BusinessException(SystemError.FINANCE_PAIDIN_17029);
        }
        if (!Objects.equals(paidIn.getApprovalStatus(),1)){
            throw new BusinessException(SystemError.FINANCE_CHARGE_17028);
        }
        paidIn.setApprovalStatus(2);
        paidIn.setModifiedId(req.getUserId());
        //提交审批
        Long approvalId = startApproval(paidIn.getId(), paidIn.getId(), req.getUserId());
        paidIn.setApprovalId(approvalId);
        boolean update = updateById(paidIn);
        if (!update){
            throw new BusinessException(SystemError.SYS_437);
        }
        return Result.success(paidIn.getId());
    }

    /**
     * 审批
     *
     * @param req
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result approval(PaidInApprovalReq req) {
        QueryWrapper<FinancePaidIn> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("approval_id",req.getApprovalId());
        queryWrapper.eq("is_deleted",0);
        FinancePaidIn paidIn = paidInMapper.selectOne(queryWrapper);
        if (paidIn == null){
            throw new BusinessException(SystemError.FINANCE_PAIDIN_17029);
        }
        if (!Objects.equals(paidIn.getApprovalStatus(),2)){
            throw new BusinessException(SystemError.FINANCE_BILL_17012);
        }
        paidIn.setModifiedId(req.getUserId());
        if (Objects.equals(req.getType(),0)){
            //撤回
            paidIn.setIsDeleted(0);
            boolean update = updateById(paidIn);
            paidInDetailMapper.cleanByPaidIn(paidIn.getId(), req.getUserId());
            if (!update){
                throw new BusinessException(SystemError.SYS_437);
            }
            Result<ApprovalCheckDTO> check = sysApprovalService.check(req.getApprovalId(), req.getUserId(), req.getType(), req.getComments());
            if (check == null || !check.getData().getIsFinish()){
                throw new BusinessException(SystemError.SYS_437);
            }
        }else{
            paidIn.setApprovalStatus(req.getType());
            boolean update = updateById(paidIn);
            if (!update){
                throw new BusinessException(SystemError.SYS_437);
            }
            Result<ApprovalCheckDTO> check = sysApprovalService.check(req.getApprovalId(), req.getUserId(), req.getType(), req.getComments());
            if (check == null || !check.getData().getIsFinish()){
                throw new BusinessException(SystemError.SYS_437);
            }
            if (Objects.equals(req.getType(),3)){
                //审批通过后的处理
                paidIn.setPayStatus(1);
                paidIn.setModifiedId(req.getUserId());
                boolean update1 = updateById(paidIn);
                if (!update1){
                    throw new BusinessException(SystemError.SYS_437);
                }
            }
        }
        return Result.success(paidIn.getId());
    }

    /**
     * 供应商往来预订单列表
     *
     * @param req
     * @return
     */
    @Override
    public Result<PageResponse<PaidInsupplierOrderListDTO>> supplierOrderList(PaidInsupplierOrderListReq req) {
        Page<PaidInsupplierOrderListDTO> iPage = new Page<>(req.getPageNo(), req.getPageSize());
        Page<PaidInsupplierOrderListDTO> page = paidInDetailMapper.querySupplierOrderListByCondition(req,iPage);
        if (CollectionUtils.isEmpty(page.getRecords())) {
            return Result.success(PageResponse.empty(page.getCurrent()));
        }
        page.getRecords().forEach(dto -> {
            //查询创建人
            UserDTO userDto = sysUserService.queryCacheUser(dto.getCreateId());
            if (userDto != null){
                dto.setCreateUserName(userDto.getFullName());
                dto.setCreateUserDept(userDto.getDept());
            }
        });
        PageResponse<PaidInsupplierOrderListDTO> result = new PageResponse<>(
                page.getRecords(),
                page.getCurrent() == 1,
                page.getTotal() <= (page.getCurrent() * page.getSize()),
                page.getTotal(),
                page.getCurrent(),
                page.getSize());
        return Result.success(result);
    }

    /**
     * 申请付款-付款预订单列表
     *
     * @param req
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<PaidInPreOrderDTO> preOrderList(PaidInPreOrderListReq req) {
        PaidInPreOrderDTO dto = new PaidInPreOrderDTO();
        if (req.getReconciliationIdList().size() == 0){
            throw new BusinessException(SystemError.SYS_428,"reconciliationIdList");
        }
        //查询指定对账单对应供应商预订单ID列表
        List<Long> orderIdList = supplierReconciliationDetailMapper.queryOrderIdListByReconciliation(req.getReconciliationIdList());
        if (CollectionUtils.isEmpty(orderIdList)){
            throw new BusinessException(SystemError.FINANCE_ERROR_17031);
        }
        //查询供应商预订单
        Result<List<SupplierOrderDTO>> result = null;
        try {
            result = supplierOrderService.selectListByIds(orderIdList);
        }catch (Exception e){
            throw new BusinessException(SystemError.SYS_431,"供应商预订单");
        }
        if (result.isSuccess()){
            List<SupplierOrderSourceDTO> list = EntityUtil.copyList(result.getData(), SupplierOrderSourceDTO.class);
            if (CollectionUtils.isNotEmpty(list)){
                //實際應付币种金额统计
                List<CurrencyAmountCountDTO> currencyAmountList = new ArrayList<>();
                //付款预订单列表
                List<PaidInPreOrderListDTO> preOrderList = new ArrayList<>();
                //遍历返回数据
                for (SupplierOrderSourceDTO sourceDTO : list){
                    PaidInPreOrderListDTO preOrderDTO = EntityUtil.copy(sourceDTO,PaidInPreOrderListDTO.class);
                    preOrderDTO.setOrderId(sourceDTO.getId());
                    preOrderDTO.setCurrencyName(sourceDTO.getCurrency());
                    preOrderDTO.setResourceInfo(sourceDTO.getResourceProductName());
                    preOrderDTO.setOrderCreateTime(sourceDTO.getGmtCreate());
                    preOrderDTO.setPayableAmount(sourceDTO.getPayableAmount());
                    if (StringUtils.isNotBlank(sourceDTO.getCreateUser())){
                        String[] split = sourceDTO.getCreateUser().split("/");
                        preOrderDTO.setCreateUserName(split[0]);
                        preOrderDTO.setCreateUserDept(split[1]);
                    }
                    //获取未付清供应商预订单最新付款记录
                    FinancePaidInDetail lastsOne = paidInDetailMapper.getLastestOne(sourceDTO.getId());
                    if (lastsOne != null){
                        preOrderDTO.setReconciliationNumber(lastsOne.getReconciliationNumber());
                        //未付金额
                        BigDecimal unpayAmount = BigDecimal.ZERO;
                        //已付金额
                        BigDecimal paidAmount = lastsOne.getPaidAmount().add(lastsOne.getPayAmount());
                        if (paidAmount.compareTo(lastsOne.getPayableAmount()) >= 0){
                            //已经付完了
                            //查询付款单
                            FinancePaidIn paidIn = getById(lastsOne.getPaidInId());
                            paidIn.setPayStatus(2);
                            preOrderDTO.setPayStatus(2);
                            preOrderDTO.setPayAmount(BigDecimal.ZERO);
                            paidIn.setModifiedId(req.getUserId());
                            //更新付款单未已付清
                            boolean update = updateById(paidIn);
                            if (!update){
                                throw new BusinessException(SystemError.SYS_437);
                            }
                        }else{
                            preOrderDTO.setPayStatus(1);
                            //未付金额
                            unpayAmount = lastsOne.getPayableAmount().subtract(paidAmount);
                            preOrderDTO.setPayAmount(unpayAmount);
                            //實際應付币种金额统计
                            if (CollectionUtils.isEmpty(currencyAmountList)){
                                //保存属性
                                CurrencyAmountCountDTO currencyAmountCountDTO = saveCurrencyAmountCount(lastsOne,unpayAmount);
                                currencyAmountList.add(currencyAmountCountDTO);
                            }else{
                                //是否新币种
                                boolean isNew = true;
                                for (CurrencyAmountCountDTO amountCountDTO : currencyAmountList){
                                    if (Objects.equals(lastsOne.getCurrencyId(),amountCountDTO.getId())){
                                        //订单类型1 预订,2 退订
                                        if (Objects.equals(lastsOne.getOrderType(),1)){
                                            amountCountDTO.setAmount(amountCountDTO.getAmount().add(unpayAmount));
                                        }else{
                                            amountCountDTO.setAmount(amountCountDTO.getAmount().subtract(unpayAmount));
                                        }
                                        isNew = false;
                                    }
                                }
                                //新增币种统计
                                if (isNew){
                                    //保存属性
                                    CurrencyAmountCountDTO currencyAmountCountDTO = saveCurrencyAmountCount(lastsOne,unpayAmount);
                                    currencyAmountList.add(currencyAmountCountDTO);
                                }
                            }
                        }
                        preOrderDTO.setPaidAmount(paidAmount);
                        preOrderDTO.setUnpayAmount(unpayAmount);
                    }else{
                        //查询供应商对账单
                        ReconciliationDTO reconciliationDTO = supplierReconciliationDetailMapper.queryBySupplierOrder(sourceDTO.getId());
                        if (reconciliationDTO != null){
                            preOrderDTO.setReconciliationId(reconciliationDTO.getReconciliationId());
                            preOrderDTO.setReconciliationNumber(reconciliationDTO.getReconciliationNumber());
                        }
                        preOrderDTO.setPayStatus(0);
                        preOrderDTO.setPaidAmount(BigDecimal.ZERO);
                        preOrderDTO.setUnpayAmount(BigDecimal.ZERO);
                        preOrderDTO.setPayAmount(sourceDTO.getPayableAmount());
                    }
                    preOrderList.add(preOrderDTO);
                }
                //實際應付
                dto.setCurrencyAmountList(currencyAmountList);
                //付款预订单列表
                dto.setPreOrderList(preOrderList);
                dto.setSize(preOrderList.size());
            }
        }
        return Result.success(dto);
    }

    /**
     * 根据ID列表预订单付款详情列表
     *
     * @param idList
     * @return
     */
    @Override
    public List<PaidInStaticsDTO> getStaticsByIds(List<Long> idList) {
        List<PaidInStaticsDTO> list = new ArrayList<>();
        idList.forEach(orderId -> {
            PaidInStaticsDTO dto = new PaidInStaticsDTO();
            dto.setId(orderId);
            //未付金额
            BigDecimal unpayAmount = BigDecimal.ZERO;
            //已付金额
            BigDecimal paidAmount = BigDecimal.ZERO;
            //获取未付清供应商预订单最新付款记录
            FinancePaidInDetail lastsOne = paidInDetailMapper.getLastestOne(orderId);
            if (lastsOne != null){
                //已付金额
                paidAmount = lastsOne.getPaidAmount().add(lastsOne.getPayAmount());
                if (paidAmount.compareTo(lastsOne.getPayableAmount()) < 0){
                    //未付金额
                    unpayAmount = lastsOne.getPayableAmount().subtract(paidAmount);
                    if (paidAmount.compareTo(BigDecimal.ZERO) == 0){
                        dto.setPayStatus(1);
                    }else{
                        dto.setPayStatus(2);
                    }
                }else{
                    dto.setPayStatus(3);
                }
                dto.setPaidAmount(paidAmount);
                dto.setUnpayAmount(unpayAmount);
                dto.setCurrency(lastsOne.getCurrencyName());
            }
            list.add(dto);
        });
        return list;
    }

    /**
     * 保存币种金额统计属性
     * @param lastsOne
     * @param unpayAmount
     * @return
     */
    private CurrencyAmountCountDTO saveCurrencyAmountCount(FinancePaidInDetail lastsOne, BigDecimal unpayAmount) {
        CurrencyAmountCountDTO currencyAmountCountDTO = new CurrencyAmountCountDTO();
        currencyAmountCountDTO.setId(lastsOne.getCurrencyId());
        currencyAmountCountDTO.setCurrency(lastsOne.getCurrencyName());
        //订单类型1 预订,2 退订
        if (Objects.equals(lastsOne.getOrderType(),1)){
            currencyAmountCountDTO.setAmount(unpayAmount);
        }else{
            currencyAmountCountDTO.setAmount(unpayAmount.negate());
        }
        return currencyAmountCountDTO;
    }


    /**
     * 发起审批流程
     * @param id
     * @param businessId
     * @param userId
     */
    private Long startApproval(Long id, Long businessId, Long userId) {
        Map<String, Object> extendParams = new HashMap<>();
        extendParams.put("id", id);
        try{
            Result<ApprovalStartDTO> approvalResult = sysApprovalService.start(SystemBusinessType.FINANCE.getCode(),
                    SysApprovalType.REALPAYMENT_FINANCE.getCode(), businessId,
                    userId, null, JSON.toJSONString(extendParams));
            if (!approvalResult.isSuccess()) {
                throw new BusinessException(SystemError.CUSTOM_ORDER_4044);
            }
            return approvalResult.getData().getApprovalId();
        }catch (Exception e){
            throw new BusinessException(SystemError.SYS_422);
        }
    }

}
